package cn.xinfei.xdecision.engine.runner.datax;

import cn.xinfei.xdecision.constant.EngineResultEnum;
import cn.xinfei.xdecision.data.RiskDataApiInterface;
import cn.xinfei.xdecision.engine.runner.context.PipelineContextHolder;
import cn.xinfei.xdecision.engine.runner.context.XDecisionContext;
import cn.xinfei.xdecision.engine.runner.metadata.PrometheusTagsConstants;
import cn.xinfei.xdecision.engine.runner.producer.DecisionProducer;
import cn.xinfei.xdecision.engine.runner.service.DecisionDataQueryService;
import cn.xinfei.xdecision.engine.runner.service.DecisionResultService;
import cn.xinfei.xdecision.model.VariableApiRequest;
import com.alibaba.fastjson.JSONObject;
import com.dianping.cat.Cat;
import com.dianping.cat.message.Transaction;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Metrics;
import io.micrometer.core.instrument.Tags;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;

import java.util.Set;
import java.util.concurrent.ConcurrentMap;
import cn.xinfei.xdecision.common.utils.util.JsonUtil;

@Data
@Slf4j
public abstract class RiskDataApiAdapter<REQ, RES> {

    @Autowired
    private MeterRegistry meterRegistry;

    @Autowired
    private RiskDataApiInterface riskDataApiInterface;

    @Autowired
    private DecisionResultService decisionResultService;

    @Autowired
    private DecisionDataQueryService decisionDataQueryService;

    @Autowired
    private DecisionProducer decisionProducer;

    public enum CollectTypeEnum {
        PRE, REAL, CREDIT_APPLY, CREDIT_FETCH
    }

    protected abstract Boolean exec(VariableApiRequest variableApiRequest)throws Exception ;

    public Boolean queryFieldValue(Set<String> fields, String type) throws Exception {
        if (PipelineContextHolder.isInvokeRemote() == false) {
            log.info("测试数据不发起远程调用");
            return true;
        }


        if (CollectionUtils.isEmpty(fields)) {
            log.info("不需要加载变量，fields is empty");
//            meterRegistry.counter("xengine_xdata_stop_total", PrometheusTagsConstants.XDATA_API_TOTAL_TAGS).increment();
            return true;
        }

        boolean result = true;
        String response = "";
        long respond = 0;
        String simpleName = this.getClass().getSimpleName();
        Transaction transaction = Cat.newTransaction("xengine_xdata", simpleName);
        Long start = System.currentTimeMillis();
        VariableApiRequest variableApiRequest = new VariableApiRequest();
        try {

            String decisionId = PipelineContextHolder.getDecisionId();
            variableApiRequest.setVarCodes(fields);
            variableApiRequest.setRequestId(decisionId);


            ConcurrentMap<String, Object> contextValue = PipelineContextHolder.getContextValue();
            ObjectMapper mapper = new ObjectMapper();
            String jsonString = mapper.writeValueAsString(contextValue);
            JSONObject obj = mapper.readValue(jsonString, JSONObject.class);

            variableApiRequest.setInputParams(obj);
            result = exec(variableApiRequest);
            transaction.setStatus(Transaction.SUCCESS);

        } catch (Exception e) {
            Long end = System.currentTimeMillis();
            log.error("RiskDataApiAdapter exception. error={},respond={},type={},variableApiRequest={}", e.getMessage(), end - start, type, JsonUtil.toJson(variableApiRequest), e);

            XDecisionContext.getContext().getStateContext().setEngineResultEnum(EngineResultEnum.DATASOURCE_EXCEPTION);
            result = false;
            Cat.logError(e);
            transaction.setStatus(e);
            meterRegistry.counter("xdecision_data_error_total", PrometheusTagsConstants.XDATA_API_RESPOND_TAGS.and(Tags.of("type", simpleName))).increment();

            throw e;
        } finally {
            Long end = System.currentTimeMillis();
            respond = end - start;

            Metrics.gauge("xdecision_data_respond", PrometheusTagsConstants.XDATA_API_RESPOND_TAGS.and(Tags.of("type", simpleName)), respond);

            transaction.setDurationInMillis(respond);
            transaction.complete();

            log.info("type:{},dataServerDuration:{}", type, respond);
//            decisionProducer.sendQueryLog(fields, respond, response, type);
        }
        return result;
    }


}
